import ifcopenshell.geom
import ifcopenshell.util.element
import numpy as np

# 创建几何设置对象
settings = ifcopenshell.geom.settings()
settings.USE_PYTHON_OPENCASCADE = True
# settings.set(settings.USE_PYTHON_OPENCASCADE, True)
# settings.set(settings.USE_WORLD_COORDS, True)

total_volume = 0.0


class Mesh:
    def __init__(self, vertices, faces):
        self.vertices = vertices
        self.faces = faces

    def __str__(self):
        return f"Mesh with {len(self.vertices)} vertices and {len(self.faces)} faces."

    def __repr__(self):
        return f"Mesh(vertices={self.vertices}, faces={self.faces})"


def calculate_wall_volume(wall):
    # 使用三角网格计算复杂墙体的体积
    if wall.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, wall)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_beam_volume(beam):
    # 使用三角网格计算复杂梁的体积
    shape = ifcopenshell.geom.create_shape(settings, beam)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_slab_volume(slab):
    # 使用三角网格计算复杂板的体积
    shape = ifcopenshell.geom.create_shape(settings, slab)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_column_volume(column):
    # 使用三角网格计算复杂柱的体积
    shape = ifcopenshell.geom.create_shape(settings, column)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_door_volume(door):
    return 0


def calculate_window_volume(window):
    return 0


def calculate_stair_volume(stair):
    if stair.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, stair)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_stair_flight_volume(stair_flight):
    if stair_flight.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, stair_flight)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_flow_segment_volume(flow_segment):
    if flow_segment.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, flow_segment)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_building_element_proxy_volume(proxy):
    if proxy.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, proxy)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_distribution_control_element_volume(element):
    if element.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, element)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_flow_fitting_volume(flow_fitting):
    if flow_fitting.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, flow_fitting)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_flow_terminal_volume(flow_terminal):
    if flow_terminal.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, flow_terminal)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_railing_volume(railing):
    if railing.Representation is None:
        return 0
    shape = ifcopenshell.geom.create_shape(settings, railing)
    geometry = shape.geometry
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_building_volume(building):
    return 0


def calculate_building_storey_volume(building_storey):
    return 0


# def convert_geometry_to_mesh(geometry):
#    vertices = []
#    faces = []
#
#    # 打印顶点信息进行调试
#    print("Vertices:", geometry.verts)
#
#    # 打印面的信息进行调试
#    print("Faces:", geometry.faces)
#
#    # 确保每个顶点是一个三元组（x, y, z）
#    for i in range(0, len(geometry.verts), 3):
#        vertex = [geometry.verts[i], geometry.verts[i + 1], geometry.verts[i + 2]]
#        vertices.append(vertex)
#
#    # 确保每个面是由三个顶点索引组成的三角形
#    for i in range(0, len(geometry.faces), 3):
#        face = [geometry.faces[i], geometry.faces[i + 1], geometry.faces[i + 2]]
#        faces.append(face)
#
#    return Mesh(vertices, faces)


def convert_geometry_to_mesh(geometry):
    vertices = []
    faces = []

    # 将顶点信息转换为三元组（x, y, z）
    verts = np.array(geometry.verts).reshape(-1, 3)
    for vert in verts:
        vertices.append([vert[0], vert[1], vert[2]])

    # 将面信息转换为三角形顶点索引
    faces = np.array(geometry.faces).reshape(-1, 3).tolist()

    return Mesh(vertices, faces)


def calculate_volume_from_mesh(mesh):
    #    print('mesh:', mesh)
    volume = 0.0
    for face in mesh.faces:
        v0 = np.array(mesh.vertices[face[0]])
        v1 = np.array(mesh.vertices[face[1]])
        v2 = np.array(mesh.vertices[face[2]])
        volume += np.dot(v0, np.cross(v1, v2)) / 6.0
    return float(abs(volume))  # 确保返回值为标准 Python 浮点数


def calculate_volume_from_geometry(geometry):
    mesh = convert_geometry_to_mesh(geometry)
    return calculate_volume_from_mesh(mesh)


def calculate_volume(product):
    try:
        if product.is_a("IfcWall"):
            return calculate_wall_volume(product)
        elif product.is_a("IfcBeam"):
            return calculate_beam_volume(product)
        elif product.is_a("IfcSlab"):
            return calculate_slab_volume(product)
        elif product.is_a("IfcColumn"):
            return calculate_column_volume(product)
        elif product.is_a("IfcDoor"):
            return calculate_door_volume(product)
        elif product.is_a("IfcWindow"):
            return calculate_window_volume(product)
        elif product.is_a("IfcStair"):
            return calculate_stair_volume(product)
        elif product.is_a("IfcStairFlight"):
            return calculate_stair_flight_volume(product)
        elif product.is_a("IfcFlowSegment"):
            return calculate_flow_segment_volume(product)
        elif product.is_a("IfcBuildingElementProxy"):
            return calculate_building_element_proxy_volume(product)
        elif product.is_a("IfcDistributionControlElement"):
            return calculate_distribution_control_element_volume(product)
        elif product.is_a("IfcFlowFitting"):
            return calculate_flow_fitting_volume(product)
        elif product.is_a("IfcFlowTerminal"):
            return calculate_flow_terminal_volume(product)
        elif product.is_a("IfcRailing"):
            return calculate_railing_volume(product)
        elif product.is_a("IfcBuilding"):
            return calculate_building_volume(product)
        elif product.is_a("IfcBuildingStorey"):
            return calculate_building_storey_volume(product)
        else:
            if product.Representation is None:
                return 0
            shape = ifcopenshell.geom.create_shape(settings, product)
            return calculate_volume_from_geometry(shape.geometry)
    except Exception as e:
        print(f"Error calculating volume for {product.GlobalId}: {e}")
        return 0
